﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using iSteam.Sdk.Data;

namespace iSteam.Sdk
{
    internal class Core : BaseRequest, ICore
    {
        public Core(AccessToken accessToken, LoginToken loginToken): base (accessToken, loginToken)
        {
        }
        public Core() : base()
        {
        }

        public List<Friend> GetFriends(String steamid = null)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return null;
            if (string.IsNullOrEmpty(steamid)) steamid = LoginToken.SteamId;

            String response =
                SteamRequest(string.Format(Constants.SteamFriendsListUrl, AccessToken.Token, steamid));

            return response != null ? DataSerialise.Decrypt<Friends>(response).Details : new List<Friend>();
        }

        public List<User> GetUserInfo(List<String> steamids)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return null;

            String response =
                SteamRequest(String.Format(Constants.SteamUserInfoUrl, AccessToken.Token,
                                           String.Join(",",
                                                       steamids.GetRange(0, Math.Min(steamids.Count, 100)).ToArray())));
            if (response != null)
            {
                var data = DataSerialise.Decrypt<Users>(response);

                if (data != null && data.Details != null && data.Details.Count > 0)
                {
                    var users = data.Details;

                    // Requests are limited to 100 steamids, so issue multiple requests
                    if (steamids.Count > 100)
                        users.AddRange(GetUserInfo(steamids.GetRange(100, Math.Min(steamids.Count - 100, 100))));

                    return users;
                }
            }
            return new List<User>();
        }

        public List<User> GetUserInfo(List<Friend> friends)
        {
            var steamids = new List<String>(friends.Count);
            steamids.AddRange(friends.Select(f => f.SteamId));
            return GetUserInfo(steamids);
        }

        public User GetUserInfo(String steamid = null)
        {
            if (steamid == null) steamid = LoginToken.SteamId;
            return GetUserInfo(new List<String>(new[] { steamid }))[0];
        }

        public Bitmap GetUserAvatar(User user, AvatarSize size = AvatarSize.Small)
        {
            if (user.AvatarUrlClean.Length == 0) return null;

            try
            {
                return GetAvatar(user.AvatarUrlUnclean, size);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public Bitmap GetGroupAvatar(GroupInfo group, AvatarSize size = AvatarSize.Small)
        {
            return GetAvatar(group.AvatarUrlClean, size);
        }

        public List<Group> GetGroups(String steamid = null, GroupMembership groupMembership = GroupMembership.Member)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return null;
            if (steamid == null) steamid = LoginToken.SteamId;

            String response =
                SteamRequest(string.Format(Constants.SteamGroupListUrl, AccessToken.Token, steamid));

            if (response != null)
            {
                var data = DataSerialise.Decrypt<Groups>(response);

                if (data != null && data.Details != null && data.Details.Count > 0)
                {
                    switch (groupMembership)
                    {
                        case GroupMembership.All:
                            return data.Details;
                        default:
                            {
                                return data.Details.Where(@group => @group.Relationship.Equals(groupMembership.ToString())).ToList();
                            }
                    }
                }
            }
            return new List<Group>();
        }

        public AdditionalGroupInfo GetAdditionalGroupInfo(string steamId)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return null;

            String response =
                SteamRequest(string.Format(Constants.SteamAdditionalGroupInfoUrl, steamId), null, Source.Community);
            
            if (response != null)
            {
                var data = DataSerialise.DeserializeFromXml<AdditionalGroupInfo>(response);
                return data;
            }
            return null;
        }

        public List<GroupInfo> GetGroupInfo(List<String> steamids)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return null;

            String response =
                SteamRequest(string.Format(Constants.SteamGroupInfoUrl, AccessToken.Token,
                                           String.Join(",",
                                                       steamids.GetRange(0, Math.Min(steamids.Count, 100)).ToArray())));

            if (response != null)
            {
                var data = DataSerialise.Decrypt<GroupInfos>(response);

                if (data != null && data.Details != null && data.Details.Count > 0)
                {
                    var groups = data.Details;
                    // Requests are limited to 100 steamids, so issue multiple requests
                    if (steamids.Count > 100)
                        groups.AddRange(GetGroupInfo(steamids.GetRange(100, Math.Min(steamids.Count - 100, 100))));

                    return groups;
                }
            }
            return new List<GroupInfo>();
            
        }

        public List<GroupInfo> GetGroupInfo(List<Group> groups)
        {
            var steamids = new List<String>(groups.Count);
            steamids.AddRange(groups.Select(g => g.SteamId));
            return GetGroupInfo(steamids);
        }

        public GroupInfo GetGroupInfo(String steamid)
        {
            return GetGroupInfo(new List<String>(new String[] { steamid }))[0];
        }

        public bool SendMessage(User user, String message)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return false;

            String response = SteamRequest(Constants.SteamMessageUrl,
                                           string.Format(Constants.SteamUserMessagePost, AccessToken.Token,
                                                         LoginToken.Uid, Uri.EscapeDataString(message), user.SteamId));
                                           

            if (response != null)
            {
                var data = DataSerialise.Decrypt<NotificationMessage>(response);
                return data != null && data.Message.Equals("OK");
            }

            return false;
        }

        public bool SendMessage(String steamid, String message)
        {
            var user = new User {SteamId = steamid};
            return SendMessage(user, message);
        }

        public ServerInfo GetServerInfo()
        {
            String response = SteamRequest(Constants.SteamServerInfoUrl);

            return response != null ? DataSerialise.Decrypt<ServerInfo>(response) : null;
        }

        public bool SendTypingNotification(User user)
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return false;

            String response = SteamRequest(Constants.SteamMessageUrl,
                                           string.Format(Constants.SteamNotificationMessagePost, AccessToken.Token,
                                                         LoginToken.Uid, user.SteamId));

            if (response != null)
            {
                var data = DataSerialise.Decrypt<NotificationMessage>(response);
                return data != null && data.Message.Equals("OK");
            }

            return false;
        }
        
        internal PollMessage Poll()
        {
            if (string.IsNullOrEmpty(LoginToken.Uid)) return null;

            String response = SteamRequest(Constants.SteamPollUrl,
                                           string.Format(Constants.SteamPollPost, AccessToken.Token, LoginToken.Uid,
                                                         MessageCount));

            if (response != null)
            {
                var data = DataSerialise.Decrypt<PollMessage>(response);
                Message = data.MessageLast;
                return data;
            }

            return null;
        }

        #region *** Private Methods ***

        private static Bitmap GetAvatar(string url, AvatarSize size)
        {
            var client = new WebClient();

            Stream stream;
            switch (size)
            {
                case AvatarSize.Small:
                    stream = client.OpenRead(url + ".jpg");
                    break;
                case AvatarSize.Medium:
                    stream = client.OpenRead(url + "_medium.jpg");
                    break;
                default:
                    stream = client.OpenRead(url + "_full.jpg");
                    break;
            }

            var avatar = new Bitmap(stream);
            stream.Flush();
            stream.Close();

            return avatar;
        }

        #endregion
    }

}
